/**
 * This software was produced for the U. S. Government
 * under Contract No. FA8721-09-C-0002, and is
 * subject to the Rights in Noncommercial Computer Software
 * and Noncommercial Computer Software Documentation Clause
 * (DFARS) 252.227-7014 (JUN 1995)
 * 
 * (c) 2009 The MITRE Corporation. All Rights Reserved.
 *
 * SPMIF to OPNET Translator
 * Author: EWALTERS
 * Created: 1:07:21 PM, Aug 1, 2007
 * MITRE Corporation
 */
package com.mitre.spmif2opnet.analysis.ast;

import java.util.Collection;
import java.util.Hashtable;

import com.mitre.spmif2opnet.VisitorContext;
import com.mitre.spmif2opnet.analysis.Identifier;

/**
 * Top-level node class
 * NOTE: We have taken a bit of liberty with the structure of
 *  nodes by pushing probability and resources into the base
 *  class - given a valid XML source, this should present no
 *  serious issues...
 * We also use this node as a basic node!
 */
public class Node implements Visitee, Copyable<Node> {
	/**
	 * Name of the node
	 */
	private String _name;
	/**
	 * S-PMIF node id
	 */
	private String _id;
	/**
	 * Probability the node will execute (currently unused)
	 */
	private double _prob;
	/**
	 * What resources does the node require? 
	 */
	protected Hashtable<String, Double> _resources;
	
	/**
	 * Default constructor
	 * @param name node name
	 * @param id  node id
 	 * @param prob probability
	 */
	public Node(String name, String id, double prob) {
		_name = name;
		_prob = prob;
		_id = id;
		_resources = new Hashtable<String, Double>();
	}
	
	/**
	 * Constructor when we know the node will always execute
	 * @param name node name
	 * @param id   node id
	 */
	public Node(String name, String id) {
		this(name, id, 1.0);
	}
	
	/**
	 * name mutator
	 * @param name the name
	 */
	public void setName(String name) {
		_name = name;
	}
	
	/**
	 * name accessor
	 * @return the name
	 */
	public String getName() {
		return _name;
	}

	/** 
	 * Probability accessor
	 * @return the prob
	 */
	public double getProbability() {
		return _prob;
	}
	
	/**
	 * Id accessor
	 * @return the id
	 */
	public String getId() {
		return _id;
	}
	
	/**
	 * Add a resource to the node
	 * @param name resource name
	 * @param units number of service units
	 */
	public void addResource(String name, double units) {
		// Warn on duplicates
		if (_resources.containsKey(name)) {
			System.out.println("Duplicate resource " + name + " allocated for node " + _name);
		}
		// Warn on zero amount
		if (units == 0.0) {
			System.out.println("[WARNING] Zero timing specified for: " + name + "." + _name); 
		} else if (units < 0.0) {
			System.out.println("[WARNING] Negative timing specified for:  " + name + "." + _name); 
		}
		_resources.put(name, new Double(units));
	}

	/**
	 * Same as add resource, but no unit warnings
	 * @param name resource name
	 * @param units number of service units
	 */
	public void copyResource(String name, double units) {
		// Warn on duplicates
		if (_resources.containsKey(name)) {
			System.out.println("Duplicate resource " + name + " allocated for node " + _name);
		}
		_resources.put(name, new Double(units));
	}

	/**
	 * Get the resources names
	 * @return the names
	 */
	public Collection<String> getResources() {
		return _resources.keySet();
	}
	
	/**
	 * Get the services that correspond to the resource
	 * @param res_name the resource name
	 * @return the units
	 */
	public double getResourceService(String res_name) {
		Double service = _resources.get(res_name);
		return (service == null) ? 0.0 : service.doubleValue();
	}

	/**
	 * Visitor acceptor
	 */
	public <T> VisitorContext<T> accept(NodeVisitor<T> v, VisitorContext<T> c) {
		return v.visit(this, c);
	}

	/**
	 * Copy node resources
	 * @param n the node
	 */
	protected void copyResources(Node n) {
		for (String res : n._resources.keySet()) {
			this.copyResource(res, n._resources.get(res));
		}
	}

	/**
	 * Copy function
	 * @return new copy of the node, with new id
	 */
	public Node copy() {
		Node new_n = new Node(_name, Identifier.newNodeId(_id), _prob);
		new_n.copyResources(this);
		return new_n;
	}
	
}
